package com.heima.search.service.impl;

import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.util.JsonUtils;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.search.pojo.ArticleDoc;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.SearchHistoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Fuqiang
 * @since :2023-03-31
 */
@Slf4j
@Service
public class ApUserSearchServiceImpl implements ApUserSearchService {

    @Autowired
    RestHighLevelClient client;

    @Autowired
    SearchHistoryService searchHistoryService;


    private static final String INDEX_NAME = "app_info_article";

    /**
     * 数据同步, 从mysql批量导入es
     *
     * @param articleDtoList
     */
    @Override
    public void importArticle(List<ArticleDto> articleDtoList) {

        BulkRequest request = new BulkRequest();
        for (ArticleDto articleDto : articleDtoList) {
            ArticleDoc articleDoc = new ArticleDoc(articleDto);
            IndexRequest indexRequest = new IndexRequest(INDEX_NAME)
                    .id("" + articleDto.getId())
                    .source(JsonUtils.toString(articleDoc), XContentType.JSON);
            request.add(indexRequest);
        }

        try {
            client.bulk(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("article批量同步es失败:{}", ExceptionUtils.getStackTrace(e));
        }
    }

    /**
     * app用户关键词搜索
     *
     * @param dto
     * @return
     */
    @Override
    public List<ArticleDoc> searchByWords(UserSearchDto dto) {

        searchHistoryService.asyncSaveHistory(dto.getEquipmentId(), dto.getSearchWords(), dto.getId());
        SearchRequest searchRequest = buildSearchRequest(dto);
        try {
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            return parseSearchResponse(response);
        } catch (IOException e) {
            log.error("App用户es搜索出现异常:{}", ExceptionUtils.getStackTrace(e));
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    /**
     * 构建App用户关键词搜索的Search请求对象
     *
     * @param dto
     * @return
     */
    private SearchRequest buildSearchRequest(UserSearchDto dto) {
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        // 构建查询
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.multiMatchQuery(dto.getSearchWords(), "title", "content"));
        if (dto.getMinBehotTime() != null) {
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime()));
        }
        // 构建分页
        searchRequest.source().from(0);
        searchRequest.source().size(dto.getPageSize());
        // 构建排序
        searchRequest.source().sort("publishTime", SortOrder.DESC);
        // 构建高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder().field("title")
                .preTags("<b>")
                .postTags("</b>")
                .requireFieldMatch(false);
        searchRequest.source().highlighter(highlightBuilder);
        searchRequest.source().query(boolQueryBuilder);
        return searchRequest;
    }

    /**
     * 解析pp用户关键词搜索的响应对象
     *
     * @param response
     * @return
     */
    private List<ArticleDoc> parseSearchResponse(SearchResponse response) {
        List<ArticleDoc> articleDocList = new ArrayList<>();
        // 解析json
        SearchHits hits = response.getHits();
        if (hits == null) {
            return articleDocList;
        }
        SearchHit[] hitsHits = hits.getHits();

        if (hitsHits != null && hitsHits.length > 0) {
            for (SearchHit hit : hitsHits) {
                String json = hit.getSourceAsString();
                ArticleDoc articleDoc = JsonUtils.toBean(json, ArticleDoc.class);
                if (articleDoc == null) {
                    continue;
                }
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();

                if (CollectionUtils.isEmpty(highlightFields)) {
                    continue;
                }
                HighlightField highlightField = highlightFields.get("title");
                if (highlightField != null) {
                    articleDoc.setTitle(highlightField.getFragments()[0].string());
                }
                articleDocList.add(articleDoc);
            }
        }


        return articleDocList;
    }
}
